'''
Created on 2010/08/11

@author: yukiyonezawa
'''
import sys
from pyrfid.asn1.Encoder import Encoder
from pyrfid.Util.Util import Util
from pyrfid.DataProtocol.DSFID.AccessMethod.PackedObjects.FormatFlag import FormatFlag
import copy

class ObjectInfo(object):
    
    DEFUALT_IDLPO = "DEFUALT_IDLPO"
    NON_DEFAULT_IDLPO ="NON_DEFAULT_IDLPO"
    IDMPO = "IDMPO"
    
    __LENGTH_INFORMATION_EBV = 6
    __NUMBER_OF_IDS_EBV = 3
    
    __STRUCTURE_NAME = "" #this parameter is include DEAFULT_IDLPO or NON_DEFAULT_IDLPO
    
    __LENGTH_INFORMATION = ""
    __ID_VALUES_INFORMATION = ""
    
    __STRUCTURE_OF_DEFAULT_IDLPO = {"LENGTH_INFORMATION":{"OBJECT_LENGTH":"", "PAD_INDICATOR":"0"}, "NUMBER_OF_IDS":"", "ID_LISTING":list(), "ADDENDUM":""}
    __STRUCTURE_OF_NON_DEFAULT_IDLPO = {"LENGTH_INFORMATION":{"OBJECT_LENGTH":"", "PAD_INDICATOR":"0"}, "ID_LISTS":{"APPLICATION_IDENTIFIER":"", "NUMBER_OF_IDS":"", "ID_LISTING":""}, "OPTIONAL_ID_LIST":"", "CLOSING_FLAGS":""}
    __STRUCTURE_OF_IDMPO = {"ID_MAP":"", "LENGTH_INFORMATION":{"OBJECT_LENGTH":"", "PAD_INDICATOR":"0"}, "ADDENDUM":""}
    
    __binary = "" #this parameter contain __STRUCTURE_OF****
    
    def __init__(self, structure_type):
        #depending on the number of add_data_set        
        #first, build default IDLPO    
        
        print "Initialize Object Info...."
        print self.__binary        
        self.__STRUCTURE_NAME = structure_type
        if self.__STRUCTURE_NAME == FormatFlag.BASE_IDLPO:
            self.__binary = copy.deepcopy(self.__STRUCTURE_OF_DEFAULT_IDLPO)
        elif self.__STRUCTURE_NAME == FormatFlag.BASE_IDMPO:
            self.__binary = copy.deepcopy(self.__STRUCTURE_OF_IDMPO)
        else:
            raise "UNIMPLEMNTED"
    
    def build(self, defined_packed_objects, add_data_set_list):

        if self.__STRUCTURE_NAME == FormatFlag.BASE_IDLPO:
            self.__buildDefaultIDLPO(defined_packed_objects, add_data_set_list)
        elif self.__STRUCTURE_NAME == FormatFlag.BASE_IDMPO:
            self.__buildDefaultIDMPO(defined_packed_objects, add_data_set_list)
        else:
            raise "UNIMPLEMNTED"
    
    def getIDListing(self):
        if self.__STRUCTURE_NAME == FormatFlag.BASE_IDLPO:
            return self.__binary["ID_LISTING"]
        elif self.__STRUCTURE_NAME == FormatFlag.BASE_IDMPO:
            return None
        else:
            return self.__binary["ID_LISTS"]["ID_LISTING"]
        
    def getBinary(self):        
        return {"BINARY":self.__binary, "STRUCTURE_NAME":self.__STRUCTURE_NAME}
    
    def setLengthInformation(self, secondary_id, auxformat, data_session):
        #set nulldata
        self.__binary["LENGTH_INFORMATION"]["OBJECT_LENGTH"] = "000000"
        print self.getBit()
        print secondary_id.getBit()
        print auxformat.getBit()
        print data_session.getBit()
        
        all_bit = self.getBit() + secondary_id.getBit() + auxformat.getBit() + data_session.getBit()
        
        remaining_length = len(all_bit) % 8
        
        if remaining_length != 0:
            self.__binary["LENGTH_INFORMATION"]["PAD_INDICATOR"] = "1"
            data_session.setPadBit(8 - remaining_length)
            all_bit = self.getBit() + secondary_id.getBit() + auxformat.getBit() + data_session.getBit()
        
        self.__binary["LENGTH_INFORMATION"]["OBJECT_LENGTH"] = Util.convertExtensibleBitVectorToBit( len(all_bit) / 8 , self.__LENGTH_INFORMATION_EBV )        
        print self.__binary
        
    def getLengthInformation(self):
        return self.__binary["LENGTH_INFORMATION"]
    
    def getBit(self):
        
        return_bit = ""
        if self.__STRUCTURE_NAME == FormatFlag.BASE_IDLPO:
            return_bit += self.__binary["LENGTH_INFORMATION"]["OBJECT_LENGTH"]
            return_bit += self.__binary["LENGTH_INFORMATION"]["PAD_INDICATOR"]
            return_bit += self.__binary["NUMBER_OF_IDS"]
            for id in self.__binary["ID_LISTING"]:
                return_bit += id
            return_bit += self.__binary["ADDENDUM"]
        elif self.__STRUCTURE_NAME == FormatFlag.BASE_IDMPO:            
            return_bit += self.__binary["ID_MAP"]
            return_bit += self.__binary["LENGTH_INFORMATION"]["OBJECT_LENGTH"]
            return_bit += self.__binary["LENGTH_INFORMATION"]["PAD_INDICATOR"]
            return_bit += self.__binary["ADDENDUM"]
        else:
            raise "NonImplemented now!"
        
        return return_bit
    
    @classmethod
    def analyzeObjectInfo(cls, tag_id, driver, start_address, structure_type):
        
        object_info = ""
        all_data_bit = ""
        if structure_type == FormatFlag.BASE_IDLPO:
            object_info = ObjectInfo(structure_type)
            
            #Length Information
            start_address = object_info.analyzeLengthInfomation(tag_id, driver, start_address)
            object_length = Util.convertExtensibleBitVertorToInt(object_info.getLengthInformation()["OBJECT_LENGTH"], cls.__LENGTH_INFORMATION_EBV)            
            all_data = driver.readUserMemory(tag_id, start_address["NEXT_START_ADDRESS"], object_length)
            all_data_bit = Util.convertHexToBit(all_data)[start_address["NEXT_START_BIT"]:]
            #NUMBER_OF_IDS
            all_data_bit = object_info.analyzeNumberOfIDs(all_data_bit)
            all_data_bit = object_info.analyzeIDListing(all_data_bit)
            #ADDENDUM 
            #unimplemented
            #all_data_bit = object_info.analyzeAddendum(all_data_bit)
            
        elif structure_type == FormatFlag.BASE_IDMPO:
            raise "Unimplemneted"
        else:
            raise "Non Implemented"      
        
        return (object_info, all_data_bit)
        
    def analyzeLengthInfomation(self, tag_id, driver, start_address):        
        """
        extract object_length
        """
        
        extensible_bit =  Util.parseExtensibleBit(tag_id, driver, start_address, 0, self.__LENGTH_INFORMATION_EBV)
        start_address = extensible_bit["NEXT_START_ADDRESS"]        
        length_infomation = extensible_bit["EXTENSIBLE_BIT"]
        start_bit = extensible_bit["NEXT_START_BIT"]
        
        read_data = driver.readUserMemory("tag", start_address - 1, 1)
        pad_indicator = Util.convertHexToBit(read_data)[start_bit]
        
        if extensible_bit["NEXT_START_BIT"] == 7:
            start_address += 1
            start_bit = 0
        else:
            start_bit += 1
        
        self.__binary["LENGTH_INFORMATION"]["OBJECT_LENGTH"] = length_infomation
        self.__binary["LENGTH_INFORMATION"]["PAD_INDICATOR"] = pad_indicator
        
        return {"NEXT_START_ADDRESS":start_address, "NEXT_START_BIT":start_bit}
    
    
    def analyzeNumberOfIDs(self, all_data_bit):
        number_of_ids = Util.convertExtensibleBitVertorToInt(all_data_bit, self.__NUMBER_OF_IDS_EBV)
        number_of_ids_bit =  Util.convertExtensibleBitVectorToBit(number_of_ids, self.__NUMBER_OF_IDS_EBV)
        all_data_bit = all_data_bit[len(number_of_ids_bit):]
        self.__binary["NUMBER_OF_IDS"] = number_of_ids_bit
         
        return all_data_bit
        
    def analyzeIDListing(self, all_data_bit):
        
        max_address = 0
        #ID_LISTING
        number_of_ids = Util.convertExtensibleBitVertorToInt(self.__binary["NUMBER_OF_IDS"], self.__NUMBER_OF_IDS_EBV)
        
        for index in range(number_of_ids + 1):
            max_address = (index*7)+7
            self.__binary["ID_LISTING"].append(all_data_bit[index*7:(index*7)+7])
            
        all_data_bit = all_data_bit[max_address:]   
        return all_data_bit
    
    def __buildDefaultIDLPO(self, defined_packed_objects, add_data_set_list):
        #get IDValue List
        IDValueList = list()        
        #chain
        IDInfo = defined_packed_objects.getIDInfo(True)
        chain_IDString = list()
        for IDInfoList in IDInfo:
            number_of_IDString = len(IDInfoList["ID"])
            count = 0
            for OIDString in IDInfoList["ID"]:            
                for data_set in add_data_set_list:
                    if data_set.OBJECT_IDENTIFIER == Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + OIDString):
                        count += 1  
            if number_of_IDString == count:                    
                IDValueList.append(IDInfoList["Info"].getIDValue())
                chain_IDString.extend(IDInfoList["ID"])
                
        #not chain
        for data_set in add_data_set_list:
            is_consisted = False
            for OIDString in chain_IDString:
                if Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + OIDString) == data_set.OBJECT_IDENTIFIER:
                    is_consisted = True
            
            if is_consisted == False:
                info = defined_packed_objects.getIDInfoByObjectIdentifier(data_set.OBJECT_IDENTIFIER)
                IDValueList.append(info.getIDValue())

        #IDValueList
        self.__binary["NUMBER_OF_IDS"] = Util.convertExtensibleBitVectorToBit(len(IDValueList) - 1, self.__NUMBER_OF_IDS_EBV)
        
        for IDValue in IDValueList:
            self.__binary["ID_LISTING"].append(Util.convertIntToBit(int(IDValue), 7))             
        
        
    def __buildNonDefaultIDLPO(self):
        pass
    
    def __buildIDMPO(self):
        pass 
    